from pymodbus import Framer
from pymodbus.client import ModbusTcpClient as BaseModbusTcpClient
from datetime import datetime

from pymodbus.pdu import ModbusRequest

from service.client.message_queue import MessageQueue
from service.log import log


class ModbusTcpClient(BaseModbusTcpClient):
    def __init__(self, host: str, port: int = 502):
        super().__init__(host=host, port=port, framer=Framer.SOCKET)
        self.message_queue = MessageQueue(max_size=1000)

    def execute(self, request: ModbusRequest):
        # 构造PDU（功能码 + 数据）
        pdu = bytes([request.function_code]) + request.encode()

        # 构造MBAP头部
        transaction_id = self.transaction.getNextTID() & 0xFFFF  # 限制在0-65535
        protocol_id = 0x0000
        length = len(pdu) + 1  # PDU长度（已含功能码和数据）+ 从机 ID
        unit_id = request.slave_id

        mbap_header = bytearray([
            (transaction_id >> 8) & 0xFF,
            transaction_id & 0xFF,
            (protocol_id >> 8) & 0xFF,
            protocol_id & 0xFF,
            (length >> 8) & 0xFF,
            length & 0xFF,
            unit_id,
        ])

        # 完整报文
        full_request = mbap_header + pdu
        request_hex = " ".join(f"{b:02x}" for b in full_request)
        send_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
        send_str = f"[{send_time}] TX: {request_hex}"
        log.info(send_str)
        self.message_queue.enqueue(send_str)

        # 执行请求
        response = super().execute(request)

        # 处理响应
        if response:
            response_pdu = bytes([response.function_code]) + response.encode()
            response_mbap_header = bytearray([
                (transaction_id >> 8) & 0xFF,
                transaction_id & 0xFF,
                (protocol_id >> 8) & 0xFF,
                protocol_id & 0xFF,
                (len(response_pdu) >> 8) & 0xFF,
                len(response_pdu) & 0xFF,
                unit_id,
            ])
            full_response = response_mbap_header + response_pdu
            response_hex = " ".join(f"{b:02x}" for b in full_response)
            receive_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
            response_str = f"[{receive_time}] RX: {response_hex}"
            log.info(response_str)
            self.message_queue.enqueue(response_str)
        return response

    def get_latest_message(self) -> list:
        """获取最新的消息"""
        message_list = []
        while not self.message_queue.is_empty():
            message_list.append(self.message_queue.dequeue())
        return message_list
